package vip.mtdp.asset.core.dto;

import cn.hutool.core.util.StrUtil;
import lombok.Data;
import vip.mtdp.asset.api.dto.TxnDTO;
import vip.mtdp.asset.core.constants.AssetConstant;
import vip.mtdp.asset.core.constants.PostingStateEnum;
import vip.mtdp.asset.core.utils.ExprUtil;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;


/**
 * @Description
 * @Author Evans.wang
 * @since 2023/10/29 14:27
 **/
@Data
public class PostingRuleDTO implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;

    /**
     * 业务类型，如充值、提现、合约交易等
     */
    private String bizType;

    /**
     * 分录类型，用于定义txn下的子记账类型
     */
    private String journalType;

    private Integer seq;

    /**
     * 0=单边记账
     * 1=复试记账
     */
    private Integer doubleEntry;

    /**
     * instant=交易发生时，同步实时记账
     * delay=交易发生后，系统延迟记账
     * trigger=交易发生后，外部触发记账
     */
    private String method;

    private String payerAccountExpr;
    private String payerCoinExpr;
    private String payerAmountExpr;

    private String payeeAccountExpr;
    private String payeeCoinExpr;
    private String payeeAmountExpr;

    private String feeAccountExpr;
    private String feeCoinExpr;
    private String feeAmountExpr;

    /**
     * 根据交易信息 + 当前的posting rule组装分录信息
     * @param txnDTO
     * @return
     */
    public JournalDTO evaluate(TxnDTO txnDTO){
        JournalDTO journalDTO = new JournalDTO();
        journalDTO.setTxnId(txnDTO.getId());
        journalDTO.setBizType(bizType);
        journalDTO.setJournalType(journalType);
        journalDTO.setSeq(seq);
        journalDTO.setDoubleEntry(doubleEntry);
        journalDTO.setPostingMethod(method);
        journalDTO.setAccountingDate(new Date());
        //posting 时根据 method 变更状态
        journalDTO.setPostingState(PostingStateEnum.INIT.getCode());
        //区分payer/payee
        parseParty(txnDTO);

        List<JournalDTO.JournalItemDTO> journalItemDTOList = new ArrayList<>();

        //分录明细 payer
        if (StrUtil.isNotBlank(payerAccountExpr) && StrUtil.isNotBlank(payerAmountExpr) && StrUtil.isNotBlank(payerCoinExpr)){
            List<TxnDTO.TxnItemDTO> payerList = txnDTO.getPayerList();
            for (int i = 0; i < payerList.size(); i++) {
                JournalDTO.JournalItemDTO journalItemDTO = new JournalDTO.JournalItemDTO();
                Map<String, Object> data = new HashMap<>();
                data.put("txn", txnDTO);
                data.put("i", i);
                journalItemDTO.setAccountId(ExprUtil.parse(payerAccountExpr, data, Long.class));
                journalItemDTO.setAmount(ExprUtil.parse(payerAmountExpr, data, BigDecimal.class));
                journalItemDTO.setCoin(ExprUtil.parse(payerCoinExpr, data, String.class));
                journalItemDTO.setDrCr(AssetConstant.CR);
                journalItemDTOList.add(journalItemDTO);
            }
        }
        //payee
        if (StrUtil.isNotBlank(payeeAccountExpr) && StrUtil.isNotBlank(payeeAmountExpr) && StrUtil.isNotBlank(payeeCoinExpr)){
            List<TxnDTO.TxnItemDTO> payeeList = txnDTO.getPayeeList();
            for (int i = 0; i < payeeList.size(); i++) {
                JournalDTO.JournalItemDTO journalItemDTO = new JournalDTO.JournalItemDTO();
                Map<String, Object> data = new HashMap<>();
                data.put("txn", txnDTO);
                data.put("i", i);
                journalItemDTO.setAccountId(ExprUtil.parse(payeeAccountExpr, data, Long.class));
                journalItemDTO.setAmount(ExprUtil.parse(payeeAmountExpr, data, BigDecimal.class));
                journalItemDTO.setCoin(ExprUtil.parse(payeeCoinExpr, data, String.class));
                journalItemDTO.setDrCr(AssetConstant.DR);
                journalItemDTOList.add(journalItemDTO);
            }
        }
        //fee
        if (StrUtil.isNotBlank(feeAccountExpr) && StrUtil.isNotBlank(feeAmountExpr) && StrUtil.isNotBlank(feeCoinExpr) && txnDTO.getFeeAccount() != null){
            JournalDTO.JournalItemDTO journalItemDTO = new JournalDTO.JournalItemDTO();
            Map<String, Object> data = new HashMap<>();
            data.put("txn", txnDTO);
            journalItemDTO.setAccountId(ExprUtil.parse(feeAccountExpr, data, Long.class));
            journalItemDTO.setAmount(ExprUtil.parse(feeAmountExpr, data, BigDecimal.class));
            journalItemDTO.setCoin(ExprUtil.parse(feeCoinExpr, data, String.class));
            journalItemDTO.setDrCr(AssetConstant.CR);
            journalItemDTOList.add(journalItemDTO);
        }

        journalDTO.setJournalItemDTOList(journalItemDTOList);
        return journalDTO;
    }

    /**
     * 按照party 方向处理txn item数据
     * @param txnDTO
     */
    public void parseParty(TxnDTO txnDTO){
        List<TxnDTO.TxnItemDTO> payerList = new ArrayList<>();
        List<TxnDTO.TxnItemDTO> payeeList = new ArrayList<>();
        List<TxnDTO.TxnItemDTO> txnItemDTOList = txnDTO.getTxnItemDTOList();
        if (txnItemDTOList != null && !txnItemDTOList.isEmpty()){
            for (TxnDTO.TxnItemDTO txnItemDTO : txnItemDTOList) {
                if (AssetConstant.PARTY_PAYER.equals(txnItemDTO.getParty())){
                    payerList.add(txnItemDTO);
                }
                if (AssetConstant.PARTY_PAYEE.equals(txnItemDTO.getParty())){
                    payeeList.add(txnItemDTO);
                }
            }
            if (!payerList.isEmpty()){
                txnDTO.setPayerList(payerList);
            }
            if (!payeeList.isEmpty()){
                txnDTO.setPayeeList(payeeList);
            }
        }
    }

}
